﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Pap.Data;
using Pap.Data.Abstraction.Utils;
using Pap.Web.Utils;

namespace Pap.Web.Modules.Administration.ViewModel
{
    /// <summary>
    /// 
    /// </summary>
    public class ProjectDetailsViewModel : IViewModel
    {
        /// <summary>
        /// 
        /// </summary>
        IAdministrationRepository _Repository;

        /// <summary>
        /// Initializes a new instance of the <see cref="ProjectDetailsViewModel"/> class.
        /// </summary>
        /// <param name="repository">The repository.</param>
        public ProjectDetailsViewModel(IAdministrationRepository repository)
        {
            _Repository = repository;
        }

        #region stages

        /// <summary>
        /// Gets the last stage.
        /// </summary>
        /// <returns></returns>
        public IProjectStage GetLastStage()
        {
            return _Repository.GetLastStage();
        }

        /// <summary>
        /// Gets the previous stage.
        /// </summary>
        /// <param name="stage">The stage.</param>
        /// <returns></returns>
        public IProjectStage GetPreviousStage(IProjectStage stage)
        {
            return _Repository.GetPreviousStage(stage);
        }

        /// <summary>
        /// Gets the next stage.
        /// </summary>
        /// <param name="stage">The stage.</param>
        /// <returns></returns>
        public IProjectStage GetNextStage(IProjectStage stage)
        {
            return _Repository.GetNextStage(stage);
        }

        /// <summary>
        /// Gets the stage by number.
        /// </summary>
        /// <param name="stageNumber">The stage number.</param>
        /// <returns></returns>
        public IProjectStage GetStageByNumber(int stageNumber)
        {
            return _Repository.GetStageByNumber(stageNumber);
        }

        #endregion

        /// <summary>
        /// Gets the project by id.
        /// </summary>
        /// <param name="projectID">The project ID.</param>
        /// <returns></returns>
        public IProject GetProjectById(Guid projectID)
        {
            return _Repository.GetProjectById(projectID);
        }

        /// <summary>
        /// Doeses the project name exist.
        /// </summary>
        /// <param name="projectName">Name of the project.</param>
        /// <param name="projectId">The project id.</param>
        /// <returns></returns>
        public bool DoesProjectNameExist(string projectName, Guid? projectId)
        {
            Expression<Func<IProject, bool>> expression = project => project.ProjectName.ToLower() == projectName.ToLower();
            if (!projectId.HasValue)
            {
                return (_Repository.FindProjects(expression).Count() > 0);
            }
            else
            {
                IEnumerable<IProject> result = _Repository.FindProjects(expression);
                if (result.Count() == 1)
                {
                    if (result.First().ProjectID == projectId.Value)
                        return false;
                    else return true;
                }
                else return false;
            }
        }

        /// <summary>
        /// Inserts the project.
        /// </summary>
        /// <param name="projectName">Name of the project.</param>
        /// <param name="profitPercent">The profit percent.</param>
        /// <param name="parentProject">The parent project.</param>
        /// <param name="projectStages">The project stages.</param>
        public void InsertProject(string projectName, string profitPercent, string parentProject, List<object> projectStages)
        {
            using (IUnitOfWork transaction = this.GetInstance<IUnitOfWork>())
            {
                IProject project = this.GetInstance<IProject>();
                project.ProjectID = Guid.NewGuid();
                project.ProjectName = projectName;
                project.ProfitPercent = decimal.Parse(profitPercent);
                if (!string.IsNullOrEmpty(parentProject))
                    project.ParentID = _Repository.FindProjects(p => p.ProjectName == parentProject).First().ProjectID;

                //add stages
                foreach (object[] stageObj in projectStages)
                {
                    IProjectStage stage = this.GetInstance<IProjectStage>();
                    stage.ProjectStageID = Guid.NewGuid();
                    stage.Stage = (int)stageObj[0];
                    stage.AgeLimit = (int)stageObj[1];
                    stage.From = (double)stageObj[2];
                    stage.To = (double)stageObj[3];

                    project.AddStage(stage);
                }
                _Repository.CreateProject(project);

                transaction.Commit();
            }
        }

        /// <summary>
        /// Updates the project.
        /// </summary>
        /// <param name="projectId">The project id.</param>
        /// <param name="projectName">Name of the project.</param>
        /// <param name="profitPercent">The profit percent.</param>
        /// <param name="removedStages">The removed stages.</param>
        /// <param name="projectStages">The project stages.</param>
        public void UpdateProject(Guid projectId, string projectName, string profitPercent, List<int> removedStages, List<object> projectStages)
        {
            using (IUnitOfWork transaction = this.GetInstance<IUnitOfWork>())
            {
                IProject project = GetProjectById(projectId);
                project.ProjectName = projectName;
                project.ProfitPercent = decimal.Parse(profitPercent);

                foreach (var stageNumber in removedStages)
                {
                    _Repository.DeleteStage(_Repository.GetStageByNumber(stageNumber));
                }

                foreach (object[] stageObj in projectStages)
                {
                    if ((Guid)stageObj[4] == Guid.Empty)
                    {
                        IProjectStage stage = this.GetInstance<IProjectStage>();
                        stage.ProjectStageID = Guid.NewGuid();
                        stage.Stage = (int)stageObj[0];
                        stage.AgeLimit = (int)stageObj[1];
                        stage.From = (double)stageObj[2];
                        stage.To = (double)stageObj[3];

                        project.AddStage(stage);
                    }
                    else
                    {
                        IProjectStage stage = project.Stages.Single(s => s.ProjectStageID == (Guid)stageObj[4]);
                        stage.Stage = (int)stageObj[0];
                        stage.AgeLimit = (int)stageObj[1];
                        stage.From = (double)stageObj[2];
                        stage.To = (double)stageObj[3];
                    }
                }

                transaction.Commit();
            }
        }
    }
}
